import org.molamil.acto.commands.cmd.AbstractCmd;
import org.molamil.acto.core.Logger;
import org.molamil.acto.commands.CommandContext;
import org.molamil.acto.commands.CommandRequest;
import org.molamil.acto.commands.CommandResult;
import org.molamil.acto.params.ParamContext;
import org.molamil.commons.StringUtil;
import org.molamil.acto.validators.UndeclaredParamError;
import org.molamil.acto.validators.MissingParamError;
import org.molamil.acto.AppConf;
import org.molamil.acto.validators.InvalidValidatorError;
import org.molamil.acto.validators.Validator;
import org.molamil.acto.validators.ValidatorResult;
import org.molamil.acto.core.EventConstants;
import org.molamil.acto.params.ParamValidatorResult;

/**
 * @author Jorge Hernandez
 */
class org.molamil.acto.commands.cmd.AbstractValidatorCmd extends AbstractCmd {
	
	
	// Constants
	
	public static var ERROR_INVALID_VALIDATOR_CLASS:String = "ERROR: The Validator class could not be loaded: \"{className}\".";
	public static var ERROR_MISSING_PARAM:String = "ERROR: The following parameter is required to be passed for cmd \"{cmd}\": \"{param}\".";
	public static var ERROR_UNDECLARED_PARAM:String = "ERROR: The following parameter was passed but not declared for cmd \"{cmd}\": \"{param}\".";
	
	
	// Properties
	
	private static var log:Logger = Logger.getLogger("AbstractValidatorCmd");
		private var isValidated:Boolean;
	
	
	// Constructor
	
	public function AbstractValidatorCmd(context:CommandContext) {
		super(context);
		isValidated = true;
	}
	
	
	// Functions
	
	public function execute(request:CommandRequest):CommandResult {
		
		_request = request;
		
		var eventObjectStart:Object = {target: this, type: EventConstants.COMMAND_EXECUTE_START, name: _request.name};
		dispatchEvent(eventObjectStart);
		
		_result = new CommandResult();
		_result.validatorResults = validate();
		_result.isValidated = isValidated;
		
		return _result;
		
	}
	
	private function validate():Array {
		
		var results:Array = new Array();
		
		if (_context.paramsMode == CommandContext.PARAMS_STRICT) {
			for (var p:String in _request.params) {
				var b:Boolean = false;
				for (var i:Number = 0; i < context.params.length; i++) {
					var paramContext:ParamContext = _context.params[i];
					if (p == paramContext.name) {
						b = true;
						break;
					}
				}
				if (!b) {
					isValidated = false;
					var msg:String = StringUtil.replace(ERROR_UNDECLARED_PARAM, "{cmd}", _context.name);
					msg = StringUtil.replace(msg, "{param}", p);
					throw new UndeclaredParamError(msg);
				}
			}
		}
		
		for (var i:Number = 0; i < context.params.length; i++) {
			
			var paramContext:ParamContext = _context.params[i];
			
			var param:String = _request.params[paramContext.name];
			
			if (paramContext.isRequired && param == undefined) {
				log.severe("Missing parameter");
				isValidated = false;
				var msg:String = StringUtil.replace(ERROR_MISSING_PARAM, "{cmd}", _context.name);
				msg = StringUtil.replace(msg, "{param}", paramContext.name);
				throw new MissingParamError(msg);
			}
			
			if (param == null || param == "") {
				
				var result:ValidatorResult = new ValidatorResult();
				
				if (paramContext.isRequired) {
					result.isRequiredValid = false;
					result.isValid = false;
					isValidated = false;
				} else {
					result.isRequiredValid = true;
					result.isValid = true;
				}
				
				result.preSource = param;
				result.postSource = param;
				result.props = paramContext.props;
				
				var paramResult:ParamValidatorResult = new ParamValidatorResult(paramContext, result);
				results.push(paramResult);
				
				continue;
				
			} else if (paramContext.validators.length == 0) {
			
				var result:ValidatorResult = new ValidatorResult();
				result.isRequiredValid = true;
				result.isValid = true;
				result.preSource = param;
				result.postSource = param;
				result.props = paramContext.props;
				
				var paramResult:ParamValidatorResult = new ParamValidatorResult(paramContext, result);
				results.push(paramResult);
				
				continue;
				
			}
			
			for (var j:Number = 0; j < paramContext.validators.length; j++) {
				
				var validatorClassName:String = paramContext.validators[j];
				if (validatorClassName == null)
					continue;
				if (validatorClassName.indexOf(".") == -1)
					validatorClassName = AppConf.defaultValidatorsPackage + "." + validatorClassName;
				var f:Function = eval("" + validatorClassName);
				if (f == null) {
					log.severe("Invalid validator class");
					var msg:String = StringUtil.replace(ERROR_INVALID_VALIDATOR_CLASS, "{className}", validatorClassName);
					throw new InvalidValidatorError(msg);
				}
				var validator:Validator = new f();
				
				var result:ValidatorResult = new ValidatorResult();
				result = validator.validate(param, paramContext.props);
				result.isRequiredValid = true;
				
				var paramResult:ParamValidatorResult = new ParamValidatorResult(paramContext, result);
				results.push(paramResult);
				
				if (!result.isValid)
					isValidated = false;
			
			}
				
		}
		
		return results;
		
	}
	
	
	
}
